use core::{sync, time};
use std::{borrow::{Borrow, BorrowMut}, cell::{LazyCell, OnceCell, RefCell}, future::Future, marker::{PhantomData, PhantomPinned}, ops::{Add, Deref, DerefMut}, panic, pin::{pin, Pin}, sync::{atomic::{AtomicI32, Ordering}, mpsc, Arc, LazyLock, Mutex}, thread::{self, sleep, Thread}, time::{Duration, Instant}};
use futures::channel::oneshot;
use rayon::{join, prelude::*, ThreadPoolBuilder};

thread_local! {
    static FOO: RefCell<u32> = RefCell::new(1);
}

pub fn main(){
    // test_thread_local();
    // test_rayon();
}
/// 通过使用 panic::catch_unwind()方法确保线程在panic时不会导致程序退出，
/// 但是需要确保返回值是 UnwindSafe类型的
fn test_unwind(){
    let res = panic::catch_unwind(||{
        println!("panic in test_rayon");
        let dd = Box::new(9);
        let div = *dd.as_ref() - 9/2 - 5;
        let a = 2/div;
    });
    match res {
        Ok(_) => {
            println!("test_rayon ok");
        },
        Err(e) => {
            println!("test_rayon error = {:?} typeId:{:?}",e, e.type_id());
        }
    }
}
fn test_rayon(){
    // 初始化全局线程池
    let _ = ThreadPoolBuilder::new().num_threads(6)
    .thread_name(|i| format!("g-thread-{}", i))
    .build_global().inspect_err(|e|{
        eprintln!("error create global pool = {:?}", e);
    });

    let v:Vec<i32> = (0..10_000_000).collect();
    println!("v = {:?}", &v[v.len()-10..]);

    // 使用par_iter()生成一个并行计算流
    let now = Instant::now();
    let v = v.par_iter()
        .map(|e|e*2)
        .collect::<Vec<i32>>();

    println!("spent time = {}ms", now.elapsed().as_millis());
    println!("v = {:?}", &v[v.len()-10..]);

    println!("=============================");

    // 使用线程池
    let pool = ThreadPoolBuilder::new()
        .num_threads(8)
        .build().unwrap();
    // 有三种提交任务方式
    // scope() 阻塞等待任务,可获取当前 线程池对象
    // install() 阻塞等待任务
    // spawn()  提交任务 不阻塞,也没有返回值，可以用channel 来订阅执行完毕的消息

    let (tx, rx) = mpsc::channel::<()>();
    pool.spawn(move ||{
        sleep(Duration::from_secs(1));
        println!("====spawn v = {:?}", &v[v.len()-10..]);
        tx.send(()).unwrap();
    });
    let v = vec![1,2,3,4,5,6,7,8,9,10];
    let val = pool.scope( |s|{
        s.spawn(|_|{
            println!("-----spawned inner thread");
        });
        v.get(5).unwrap()
    });
    println!("val = {}", val);

    pool.install(||{
        println!("install thread");
    });

    rx.recv().unwrap();

    // -- join 使用
    println!("-----join-----");

    let j1 = ||{
        sleep(Duration::from_millis(500));
        println!("j1 run end");
        1
    };
    //j2 中 panic不会影响j1的执行
    let j2 = ||{
        sleep(Duration::from_millis(300));
        println!("j2 run end");
        panic!("j2 panic");
        2
    };
    // 同时运行两个任务
    let (r1, r2) = join(j1, j2);
    println!("r1 = {}, r2 = {}", r1, r2);

}
fn test_lazy(){
    let num = 12;
    // LazyLock用于多线程环境
    // LazyCell用于单线程环境
    // 和 OnceCell区别是 LazyLock 自带初始化逻辑，任何时候调用都会有值
    let cell = LazyLock::new(||{
        let r = tokio::runtime::Runtime::new().unwrap();
        r
    });
    let cell = Arc::new(cell);
    let t1 = cell.clone();
    let h = thread::spawn(move ||{
        t1.block_on(async move{
            println!("async num = {}", num*2);
        });
    });
    let h2 = thread::spawn(move ||{
        cell.block_on(async move{
            println!("async2 num = {}", num*2);
        });
    });
    h.join();
    h2.join();
}
fn test_once_cell(){
    let cell = OnceCell::<i32>::new();
    let a = 12;
    cell.get_or_init(||{
        a +1
    });
    println!("cell = {:?}", cell.get());
    cell.set(99).inspect_err(|e|{
        println!("error = {:?}", e);
    });
}
fn test_option(){
    let op = Some(12);
    let op = op.inspect(|f|{
        println!("op val is {}", f);
    });
    println!("op = {:?}", op);
}
/// 常量泛型参数
/// 泛型参数可以使用常量 而不仅是 trait
/// 在编译器就确定值，可以用的类型有整数类型、char、bool 等，不能是浮点类型或自定义类型
fn test_const_generic() {
    /// N 在编译器就已经确定了
    fn display_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) {
        println!("{:?}", arr);
    }
    
    let arr: [i32; 3] = [1, 2, 3];
    display_array(arr);

    let arr = [1, 2, 3,4];
    display_array(arr);
}
fn test_refcell(){
    let data = RefCell::new(5);
    {
        let a = data.borrow();
        let b = data.borrow();
        // let c = data.borrow_mut();
        println!("a = {}, b = {}", a, b);
    }
    let data2 = data.clone();
    let data3 = data.clone();
    let handler = thread::spawn(||{
        let d = data2;
        thread::sleep(Duration::from_secs(1));
        println!("t1 data:{}", d.borrow());
    });

    *data.borrow_mut() = 60;
    let data2 = data.clone();
    thread::spawn(||{
        let d = data2;
        println!("t2 data:{}", d.borrow());
    }).join().unwrap();
    
    let data = Arc::new(Mutex::new(data));
    println!("main data = {:?} data3 = {}", data.lock().unwrap().borrow(), data3.borrow());

    let data1 = data.clone();
    thread::spawn(move ||{
        let m_data = data1.lock().unwrap();
        *(*m_data).borrow_mut() = 6;
        println!("thread data = {:?}", m_data);
    // //     data.borrow_mut().replace(6);
    }).join().unwrap();

    handler.join().unwrap();

    test_str();
}
fn test_str(){
    let str = "hello老李";
    println!("str is {}", &str[..8]);
    // 获取字符串的字符长度
    println!("str.hint = {:?}", str.chars().count());
}
/// pin的作用就是在 pin在固定住的类型是 自引用类型时，可以标记为 !Unpin，
/// 他将不能获取可变引用，从而保证内存安全
/// 而对于Unpin的对象，可以获取可变引用，相当于使用上没有影响
fn test_pin(){
    #[derive(Debug,Default)]
    struct A(i32,PhantomPinned);
    let mut n = A::default() ;

    println!("n addr = {:?}", &n as *const A);
    
    let mut np = pin!(n);
    // 1. 如果A 是 !Unpin的 ，比如在自引用类型中,
    // 那么他在获取Pin对象后就不能获取可变引用了，只能获取可变引用，也就不能修改自己，从而保证内存安全
    // 2. 如果A 是 Unpin的 ，那么他在获取Pin对象后可以轻易获得可变引用修改自己
    // let mut np = np.get_mut();
    let mut np = np.deref();
    println!("np addr = {:?}", np as *const A);
    
    // (*np).0 = 10;
    
    println!("np = {:?}", np);
}
fn test_thread_local(){
    FOO.with(|f|{
        let mut bm = f.borrow_mut();
        *bm = 2;
        *bm
    });
    println!("main thread: {:?}", FOO.with(|f|*f.borrow()));

    let _ = thread::spawn(||{
        FOO.with(|f|{
            let mut bm = f.borrow_mut();
            println!("main thread: {:?} id:{:?}", bm, thread::current().id());
            *bm = 3;
        });
    }).join();
    thread::spawn(||{
        FOO.with(|f|{
            let mut bm = f.borrow_mut();
            println!("main thread: {:?} id:{:?}", bm, thread::current().id());
            *bm = 4;
        });
    }).join().unwrap();
}
/// 测试闭包的特点 
/// 1. 闭包可以捕获外部变量
///     FnOnce: 闭包只能执行一次，一般是在闭包内获取或者转移了外部变量的所有权
///     FnMut: 闭包可以执行多次,且可以修改外部变量， 是FnOnce的子集 接收FnOnce的地方也可以接收FnMut
///     Fn: 闭包可以执行多次,是FnMut的子集，接收FnMut的地方也可以接收Fn
/// 2. 闭包捕获的变量就相当于一个结构体，如果在栈上执行，那么闭包捕获的变量会与移动到栈上，如果在堆上执行，那么闭包捕获的变量移动到堆上
///     静态变量则不会移动
/// 3. 如果希望变量a被闭包捕获，且在闭包内转义或者获取了所有权，闭包结束时，变量生命周期也结束了，所以闭包类型只能是 FnOnce() 
///     如果想被执行多次，要么使a实现Copy 闭包中获得一个copy出来的变量；
///     要么闭包中不要获取捕获变量的所有权，闭包类型是FnMut() Fn() 
fn test_clourser(){
    test_fn_once();
    // test_fn_copy();
    // test_fn_mut();
    // test_fn_receive();
}
fn test_fn_receive(){
    let mut x = 1;
    let mut func = move ||{
        println!("x = {}", x);
        let x = &mut x;
        *x += 1;
    };
    func();
    test_fn_mut_receive(func);
    // 可以传到FnOnce的地方
    test_fn_once_receive(func);
    // 不能作为Fn 传参
    // test_fn_fn_receive(func);
    
    let fnn = ||{
        println!("fn");
    };
    //Fn 可以传到 FnMut的地方
    test_fn_mut_receive(fnn);
}
fn test_fn_mut_receive(mut f: impl FnMut()){
    f();
}
fn test_fn_fn_receive(mut f: impl Fn()){
    f();
}
fn test_fn_once_receive(mut f: impl FnOnce()){
    f();
}
fn test_fn_mut(){
    println!("\n test_fn_mut=====");
    #[derive(Debug)]
    struct A(i32);
    let mut a3 = A(1);
    // 打印出a3的地址
    println!("a3 addr={:?}", &a3 as *const A);
    let ba = Box::new(A(2));
    // 打印出堆上A对象的地址
    println!("box a3 addr={:?}", ba.as_ref() as *const A);

    let mut func = move||{
         let var2  = &mut a3;
         println!("var2 = {:?}", var2);
         //这里修改了值，下一次进来的时候，a3的值已经被修改了
         *var2 = A(99);

         //打印出闭包中的a3的地址
         println!("clouser a3 addr ={:?}", var2 as *const A);
     };
     func();
     func();

     //闭包放进Box中
     let mut ba = Box::new(func);
     println!("inBox=====");
     ba.as_mut()();
}
fn test_fn_copy(){
    println!("\n test_fn_copy=====");
    #[derive(Debug, Clone, Copy)]
    struct A(i32);
    let a3 = A(1);
    // 打印出a3的地址
    println!("a3 addr={:?}", &a3 as *const A);
    let ba = Box::new(A(2));
    // 打印出堆上A对象的地址
    println!("box a3 addr={:?}", ba.as_ref() as *const A);
    let func = move||{
        // 如果只是使用a3 不获取或者转移他的所有权，闭包是可以多次执行的
        // 相当于匿名结构体， 使用a3时 相当于在使用a3的引用 : &self.a3, 不会获取a3的所有权
        let var = a3.0 + 1;
        println!("var: {:?}", var);

         // 实现了copy 这里var2是一个copy出来的新变量，a3所有权没变，所以闭包也可以多次执行
         let var2  = a3;
         println!("var2 = {:?}", var2);
         println!("clouser a3 addr ={:?}", &var2 as *const A);
         
     };
     func();
     //a实现了copy可以多次执行了, 闭包类型是Fn()
     func();
}

fn test_fn_once(){
    println!("\ntest_fn_once=====");
    #[derive(Debug)]
    struct A(i32);
    let a3 = A(1);
    // 打印出a3的地址
    println!("a3 addr={:?}", &a3 as *const A);
    let ba = Box::new(A(2));
    // 打印出堆上A对象的地址
    println!("box a3 addr={:?}", ba.as_ref() as *const A);
    let func = move||{
         // 这时获取了 a3的所有权，a3已经被move了,闭包只能执行一次
         let var2  = a3;
         println!("var2 = {:?}", var2);
         println!("clouser a3 addr ={:?}", &var2 as *const A);
     };
     func();
     //再次执行会报错，因为a3已经被move了
    //  func();
}
struct Per{
    name: String,
    age: i32,
}
struct Monkey{
    name: String,
}
#[derive(Debug)]
struct NumCat{
    n1: i32,
    n2: i32
}
impl Add for NumCat{
    type Output = i32;

    fn add(self, rhs: Self) -> Self::Output {
        self.n1 + rhs.n1
    }
}